// // tools/audit-seal.c
// #define _GNU_SOURCE
// #include <stdio.h>
// #include <stdlib.h>
// #include <string.h>
// #include <stdint.h>
// #include <unistd.h>
// #include <errno.h>
// #include <sys/stat.h>
// #include <time.h>

// #include <openssl/evp.h>
// #include <openssl/pkcs12.h>
// #include <openssl/x509.h>
// #include <openssl/pem.h>
// #include <openssl/err.h>
// #include <openssl/bio.h>
// #include <openssl/buffer.h>

// #include "../../lib/gm_crypto.h"

// #define SALT_PATH "/etc/pki/audit/p12_salt"
// #define P12_PATH "/etc/pki/audit/sm2.p12"
// #define SM2_ID "1234567812345678"
// #define SALT_BYTES 16
// #define DERIVE_BYTES 32
// #define DERIVE_ITERATIONS 200000

// static void die(const char *msg)
// {
//     perror(msg);
//     exit(1);
// }
// static void diee(const char *msg)
// {
//     fprintf(stderr, "%s\n", msg);
//     exit(1);
// }

// static int sm3_file_hex(const char *path, char out_hex[65])
// {
//     const EVP_MD *sm3 = EVP_get_digestbyname("sm3");
//     if (!sm3)
//         return -1;
//     FILE *f = fopen(path, "rb");
//     if (!f)
//         return -1;
//     EVP_MD_CTX *ctx = EVP_MD_CTX_new();
//     if (!ctx)
//     {
//         fclose(f);
//         return -1;
//     }
//     if (EVP_DigestInit_ex(ctx, sm3, NULL) != 1)
//     {
//         EVP_MD_CTX_free(ctx);
//         fclose(f);
//         return -1;
//     }

//     unsigned char buf[4096];
//     size_t n;
//     while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
//     {
//         if (EVP_DigestUpdate(ctx, buf, n) != 1)
//         {
//             EVP_MD_CTX_free(ctx);
//             fclose(f);
//             return -1;
//         }
//     }
//     fclose(f);
//     unsigned char md[32];
//     unsigned int mdlen = 0;
//     if (EVP_DigestFinal_ex(ctx, md, &mdlen) != 1 || mdlen != 32)
//     {
//         EVP_MD_CTX_free(ctx);
//         return -1;
//     }
//     EVP_MD_CTX_free(ctx);
//     static const char hex[] = "0123456789abcdef";
//     for (int i = 0; i < 32; i++)
//     {
//         out_hex[i * 2] = hex[(md[i] >> 4) & 0xF];
//         out_hex[i * 2 + 1] = hex[md[i] & 0xF];
//     }
//     out_hex[64] = 0;
//     return 0;
// }

// static int build_line_index(const char *log_path, char **out_idx_path,
//                             char index_sm3_hex[65], uint64_t *out_lines)
// {
//     FILE *fp = fopen(log_path, "rb");
//     if (!fp)
//         return -1;
//     char *idx_path = NULL;
//     if (asprintf(&idx_path, "%s.idx", log_path) < 0)
//     {
//         fclose(fp);
//         return -1;
//     }
//     FILE *ix = fopen(idx_path, "w");
//     if (!ix)
//     {
//         fclose(fp);
//         free(idx_path);
//         return -1;
//     }

//     // sm3 init
//     const EVP_MD *sm3 = EVP_get_digestbyname("sm3");
//     if (!sm3)
//     {
//         fclose(fp);
//         fclose(ix);
//         free(idx_path);
//         return -1;
//     }

//     // 头部内容
//     fprintf(ix, "# audit-ins=dex v1\n");
//     fprintf(ix, "path=%s\n", log_path);
//     fprintf(ix, "hash=sm3\n");

//     // 遍历行，记录lhash,chash,off
//     unsigned char C[32] = {0};
//     uint64_t lines = 0;
//     uint64_t off = 0;

//     char *line = NULL;
//     size_t cap = 0;
//     ssize_t n;
//     while ((n = getline(&line, &cap, fp)) != -1)
//     {
//         // 计算lhash = SM3(line)
//         unsigned char L[32];
//         unsigned int lml = 0;
//         EVP_MD_CTX *c1 = EVP_MD_CTX_new();
//         if (!c1)
//         {
//             free(line);
//             fclose(fp);
//             fclose(fp);
//             fclose(ix);
//             free(idx_path);
//             return -1;
//         }
//         if (EVP_DigestInit_ex(c1, sm3, NULL) != 1 ||
//             EVP_DigestUpdate(c1, line, (size_t)n) != 1 ||
//             EVP_DigestFinal_ex(c1, L, &lml) != 1 || lml != 32)
//         {
//             EVP_MD_CTX_free(c1);
//             free(line);
//             fclose(fp);
//             fclose(ix);
//             free(idx_path);
//             return -1;
//         }
//         EVP_MD_CTX_free(c1);

//         // 更新C=SM3(C||line)
//         EVP_MD_CTX *c2 = EVP_MD_CTX_new();
//         unsigned int cml = 0;
//         if (!c2)
//         {
//             free(line);
//             fclose(fp);
//             fclose(ix);
//             free(idx_path);
//             return -1;
//         }
//         if (EVP_DigestInit_ex(c2, sm3, NULL) != 1 ||
//             EVP_DigestUpdate(c2, C, sizeof(C)) != 1 ||
//             EVP_DigestUpdate(c2, line, (size_t)n) != 1 ||
//             EVP_DigestFinal_ex(c2, C, &cml) != 1 || cml != 32)
//         {
//             EVP_MD_CTX_free(c2);
//             free(line);
//             fclose(fp);
//             fclose(ix);
//             free(idx_path);
//             return -1;
//         }
//         EVP_MD_CTX_free(c2);

//         // 转hex
//         static const char hex[] = "0123456789abcdef";
//         char Lhex[65], Chex[65];
//         for (int i = 0; i < 32; i++)
//         {
//             Lhex[i * 2] = hex[(L[i] >> 4) & 0xF];
//             Lhex[i * 2 + 1] = hex[L[i] & 0xF];
//         }
//         Lhex[64] = 0;
//         for (int i = 0; i < 32; i++)
//         {
//             Chex[i * 2] = hex[(C[i] >> 4) & 0xF];
//             Chex[i * 2 + 1] = hex[C[i] & 0xF];
//         }
//         Chex[64] = 0;

//         // 写索引行
//         fprintf(ix, "i=%llu off=%llu lhash=%s chash=%s\n",
//                 (unsigned long long)(lines + 1),
//                 (unsigned long long)off,
//                 Lhex, Chex);

//         off += (uint64_t)n;
//         lines++;
//     }
//     free(line);
//     fclose(fp);

//     // 把 records 写在头部后面（简单写法：先写，文件末尾再补一行）
//     fprintf(ix,"records=%llu\n",(unsigned long long)lines);
//     fclose(ix);

//     //计算 idx 文件的SM3
//     if(sm3_file_hex(idx_path,index_sm3_hex)!=0)
//     {
//         free(idx_path);
//         return -1;
//     }

//     if(out_lines) *out_lines=lines;
//     *out_idx_path = idx_path;
//     return 0;
// }

// static int read_salt_hexfile(const char *path, unsigned char *out, size_t outlen)
// {
//     FILE *f = fopen(path, "r");
//     if (!f)
//         return -1;
//     char buf[128];
//     if (!fgets(buf, sizeof(buf), f))
//     {
//         fclose(f);
//         return -1;
//     }
//     fclose(f);
//     size_t len = strlen(buf);
//     while (len && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
//         buf[--len] = '\0';
//     if (len / 2 != outlen)
//         return -1;
//     for (size_t i = 0; i < outlen; i++)
//     {
//         unsigned int hi, lo;
//         if (sscanf(&buf[i * 2], "%1x%1x", &hi, &lo) != 2)
//             return -1;
//         out[i] = (hi << 4) | lo;
//     }
//     return 0;
// }

// static void hexdump(const unsigned char *buf, size_t len, char *out, size_t outlen)
// {
//     static const char hex[] = "0123456789abcdef";
//     if (outlen < len * 2 + 1)
//         diee("hexdump out too small");
//     for (size_t i = 0; i < len; i++)
//     {
//         out[i * 2] = hex[(buf[i] >> 4) & 0xF];
//         out[i * 2 + 1] = hex[buf[i] & 0xF];
//     }
//     out[len * 2] = '\0';
// }

// static int derive_pass(const char *secret, const unsigned char *salt, int saltlen,
//                        int iter, unsigned char *out, int outlen)
// {
//     const EVP_MD *md = EVP_get_digestbyname("sm3");
//     if (!md)
//         diee("[ERROR] OpenSSL 未提供 sm3，无法国密派生口令");
//     if (!PKCS5_PBKDF2_HMAC(secret, strlen(secret), salt, saltlen, iter, md, outlen, out))
//         return -1;
//     return 0;
// }

// /* 计算链式 SM3：H0=0x00..00；逐行读（包含换行符原样参与计算） */
// static int sm3_chain_file(const char *path, unsigned char out32[32], uint64_t *out_lines)
// {
//     const EVP_MD *sm3 = EVP_get_digestbyname("sm3");
//     if (!sm3)
//         return -1;

//     unsigned char H[32] = {0};
//     uint64_t lines = 0;

//     FILE *fp = fopen(path, "rb");
//     if (!fp)
//         return -1;

//     char *line = NULL;
//     size_t cap = 0;
//     ssize_t n;

//     while ((n = getline(&line, &cap, fp)) != -1)
//     {
//         EVP_MD_CTX *ctx = EVP_MD_CTX_new();
//         if (!ctx)
//         {
//             fclose(fp);
//             free(line);
//             return -1;
//         }
//         if (EVP_DigestInit_ex(ctx, sm3, NULL) != 1)
//         {
//             EVP_MD_CTX_free(ctx);
//             fclose(fp);
//             free(line);
//             return -1;
//         }
//         if (EVP_DigestUpdate(ctx, H, sizeof(H)) != 1)
//         {
//             EVP_MD_CTX_free(ctx);
//             fclose(fp);
//             free(line);
//             return -1;
//         }
//         if (EVP_DigestUpdate(ctx, line, (size_t)n) != 1)
//         {
//             EVP_MD_CTX_free(ctx);
//             fclose(fp);
//             free(line);
//             return -1;
//         }
//         unsigned int mdlen = 0;
//         if (EVP_DigestFinal_ex(ctx, H, &mdlen) != 1 || mdlen != 32)
//         {
//             EVP_MD_CTX_free(ctx);
//             fclose(fp);
//             free(line);
//             return -1;
//         }
//         EVP_MD_CTX_free(ctx);
//         lines++;
//     }
//     free(line);
//     fclose(fp);

//     memcpy(out32, H, 32);
//     if (out_lines)
//         *out_lines = lines;
//     return 0;
// }

// /* base64 工具 */
// static char *b64_encode(const unsigned char *buf, size_t len)
// {
//     BIO *b64 = BIO_new(BIO_f_base64());
//     BIO *mem = BIO_new(BIO_s_mem());
//     if (!b64 || !mem)
//     {
//         if (b64)
//             BIO_free(b64);
//         if (mem)
//             BIO_free(mem);
//         return NULL;
//     }
// #ifdef BIO_FLAGS_BASE64_NO_NL
//     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
// #endif
//     BIO_push(b64, mem);
//     if (BIO_write(b64, buf, len) <= 0)
//     {
//         BIO_free_all(b64);
//         return NULL;
//     }
//     (void)BIO_flush(b64);
//     BUF_MEM *bptr = NULL;
//     BIO_get_mem_ptr(b64, &bptr);
//     char *out = malloc(bptr->length + 1);
//     memcpy(out, bptr->data, bptr->length);
//     out[bptr->length] = '\0';
//     BIO_free_all(b64);
//     return out;
// }

// static int x509_sm3_fingerprint_hex(X509 *cert, char *out, size_t outlen)
// {
//     const EVP_MD *sm3 = EVP_get_digestbyname("sm3");
//     if (!sm3)
//         return -1;
//     unsigned char *der = NULL;
//     int derlen = i2d_X509(cert, &der);
//     if (derlen <= 0)
//         return -1;
//     unsigned char md[EVP_MAX_MD_SIZE];
//     unsigned int mdlen = 0;
//     EVP_MD_CTX *ctx = EVP_MD_CTX_new();
//     if (!ctx)
//     {
//         OPENSSL_free(der);
//         return -1;
//     }
//     if (EVP_DigestInit_ex(ctx, sm3, NULL) != 1 ||
//         EVP_DigestUpdate(ctx, der, derlen) != 1 ||
//         EVP_DigestFinal_ex(ctx, md, &mdlen) != 1)
//     {
//         EVP_MD_CTX_free(ctx);
//         OPENSSL_free(der);
//         return -1;
//     }
//     EVP_MD_CTX_free(ctx);
//     OPENSSL_free(der);
//     hexdump(md, mdlen, out, outlen);
//     return 0;
// }

// /* 载入 P12 -> pkey + cert（口令是十六进制文本） */
// static int load_pkey_cert_from_p12(const char *p12_path, const char *pass_hex,
//                                    EVP_PKEY **out_pkey, X509 **out_cert)
// {
//     FILE *f = fopen(p12_path, "rb");
//     if (!f)
//         return -1;
//     PKCS12 *p12 = d2i_PKCS12_fp(f, NULL);
//     fclose(f);
//     if (!p12)
//         return -1;
//     EVP_PKEY *pkey = NULL;
//     X509 *cert = NULL;
//     if (!PKCS12_parse(p12, pass_hex, &pkey, &cert, NULL))
//     {
//         PKCS12_free(p12);
//         return -1;
//     }
//     PKCS12_free(p12);
//     *out_pkey = pkey;
//     *out_cert = cert;
//     return 0;
// }

// /* 构造规范化描述串 */
// static char *build_canonical(const char *path, const char *chain_hex,
//                              uint64_t lines, const char *key_fpr_hex,
//                             const char *index_sm3_hex)
// {
//     char *buf = NULL;
//     if (asprintf(&buf,
//                  "version=1\n"
//                  "hash=sm3\n"
//                  "sign=sm2\n"
//                  "sm2_id=%s\n"
//                  "path=%s\n"
//                  "records=%llu\n"
//                  "chain=%s\n"
//                  "key_fpr=%s\n"
//                  "index_sm3=%s\n",
//                  SM2_ID, path, (unsigned long long)lines, chain_hex, key_fpr_hex, index_sm3_hex) < 0)
//         return NULL;
//     return buf;
// }

// //---------------------------------
// static void dump_hex_prefix(const char *tag, const unsigned char *buf, size_t len)
// {
//     size_t n = len > 128 ? 128 : len;
//     fprintf(stderr, "[DBG] %s canon len=%zu hex:", tag, len);
//     for (size_t i = 0; i < n; i++)
//         fprintf(stderr, "%02x", buf[i]);
//     if (len > n)
//         fprintf(stderr, "...");
//     fputc('\n', stderr);
// }
// //---------------------------------

// int main(int argc, char **argv)
// {
//     if (argc != 2)
//     {
//         fprintf(stderr, "Usage: %s /var/log/audit/audit.log.1\n", argv[0]);
//         return 1;
//     }
//     const char *log_path = argv[1];

//     OpenSSL_add_all_algorithms();
//     ERR_load_crypto_strings();
//     if (gm_crypto_init() != 0)
//         diee("gm init failed");

//     /* 硬性要求：必须有 sm3 */
//     if (!EVP_get_digestbyname("sm3"))
//         diee("[ERROR] OpenSSL 无 sm3，无法国密封印");

//     /* 读取 salt 并派生 P12 口令（hex） */
//     unsigned char salt[SALT_BYTES];
//     if (read_salt_hexfile(SALT_PATH, salt, SALT_BYTES) != 0)
//         diee("read salt failed");
//     char *secret = getpass("Enter master passphrase (for P12): ");
//     if (!secret || !*secret)
//         diee("empty passphrase");
//     unsigned char derived[DERIVE_BYTES];
//     if (derive_pass(secret, salt, sizeof(salt), DERIVE_ITERATIONS, derived, sizeof(derived)) != 0)
//         diee("PBKDF2(SM3) failed");
//     char passhex[DERIVE_BYTES * 2 + 1];
//     hexdump(derived, sizeof(derived), passhex, sizeof(passhex));
//     OPENSSL_cleanse(secret, strlen(secret));

//     /* 载入 SM2 私钥与证书 */
//     EVP_PKEY *pkey = NULL;
//     X509 *cert = NULL;
//     if (load_pkey_cert_from_p12(P12_PATH, passhex, &pkey, &cert) != 0)
//         diee("load P12 failed (passphrase wrong?)");

//     /* 基本校验：必须是 SM2 曲线 */
//     EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey);
//     if (!eckey)
//         diee("[ERROR] P12 不是 EC/SM2 私钥");
//     const EC_GROUP *grp = EC_KEY_get0_group(eckey);
//     if (!grp || EC_GROUP_get_curve_name(grp) != NID_sm2)
//         diee("[ERROR] 私钥不是 SM2 曲线");

//     /* 计算链式 SM3 */
//     unsigned char chain[32];
//     uint64_t lines = 0;
//     if (sm3_chain_file(log_path, chain, &lines) != 0)
//         diee("compute chain failed");
//     char chain_hex[65];
//     hexdump(chain, 32, chain_hex, sizeof(chain_hex));

//     /* 证书指纹（SM3） */
//     char fpr_hex[65];
//     if (x509_sm3_fingerprint_hex(cert, fpr_hex, sizeof(fpr_hex)) != 0)
//         diee("fingerprint failed");

//     // === 生成行级索引，并将其 SM3 纳入 seal ===
//     char *idx_path = NULL;
//     char idx_sm3_hex[65];
//     uint64_t lines_by_idx = 0;
//     if(build_line_index(log_path,&idx_path,idx_sm3_hex,&lines_by_idx)!=0)
//         diee("build insex failed");
//     if(lines_by_idx!=lines)
//     {
//         fprintf(stderr,"[WARN] index lines(%llu) != chain lines(%llu)\n",
//                 (unsigned long long)lines_by_idx,(unsigned long long)lines);
//     }

//     /* 规范串 */
//     char *canon = build_canonical(log_path, chain_hex, lines, fpr_hex,idx_sm3_hex);
//     if (!canon)
//         diee("asprintf failed");

//     //-----------------------------------
//     dump_hex_prefix("seal", (const unsigned char *)canon, strlen(canon));
//     //-----------------------------------

//     /* 用 SM2+SM3 做签名（强制 SM2/SM3） */
//     unsigned char *sig = NULL;
//     size_t siglen = 0;

//     fprintf(stderr, "[DBG] seal canon len=%zu\n", strlen(canon));
//     if (gm_sm2_sign(pkey, (const unsigned char*)canon, strlen(canon),
//                 SM2_ID, &sig, &siglen) != 0)
//         diee("SM2 sign failed");
//     //----------------------------------------------

//     /* 自验签（同一进程、同一 canon）——如果这里都失败，说明签名流程/控件仍有问题 */
//     {
//         EVP_PKEY *pub_self = X509_get_pubkey(cert);
//         if (!pub_self)
//             diee("X509_get_pubkey(self) failed");

//         int vself = gm_sm2_verify(pub_self,
//                                   (const unsigned char *)canon, strlen(canon),
//                                   SM2_ID, sig, siglen);
//         EVP_PKEY_free(pub_self);
//         if (vself != 1)
//         {
//             diee("[INTERNAL] self-verify failed (sign/verify parameters mismatch)");
//         }
//     }

//     //----------------------------------------------
//     char *sig_b64 = b64_encode(sig, siglen);
//     OPENSSL_free(sig);

//     /* 证书 DER -> base64 */
//     unsigned char *der = NULL;
//     int derlen = i2d_X509(cert, &der);
//     if (derlen <= 0)
//         diee("i2d_X509 failed");
//     char *cert_b64 = b64_encode(der, derlen);
//     OPENSSL_free(der);

//     /* 写 seal 文件 */
//     char *seal_path = NULL;
//     if (asprintf(&seal_path, "%s.seal", log_path) < 0)
//         diee("asprintf seal");
//     FILE *sf = fopen(seal_path, "w");
//     if (!sf)
//         die("fopen seal");
//     fprintf(sf,
//             "# audit-seal v1 (SM2/SM3)\n"
//             "version=1\n"
//             "hash=sm3\n"
//             "sign=sm2\n"
//             "sm2_id=%s\n"
//             "path=%s\n"
//             "records=%llu\n"
//             "chain=%s\n"
//             "key_fpr=%s\n"
//             "index_sm3=%s\n"
//             "cert_der_base64=%s\n"
//             "sig_base64=%s\n",
//             SM2_ID, log_path, (unsigned long long)lines, chain_hex, fpr_hex,
//             idx_sm3_hex,cert_b64, sig_b64);
//     fclose(sf);
//     chmod(seal_path, 0600);

//     fprintf(stderr, "[OK] sealed %s -> %s\n", log_path, seal_path);

//     free(seal_path);
//     free(sig_b64);
//     free(cert_b64);
//     free(canon);
//     X509_free(cert);
//     EVP_PKEY_free(pkey);
//     gm_crypto_cleanup();
//     return 0;
// }



